package common;


import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.LinkedHashMap;
import java.util.List;

import cluedo.Card;
import cluedo.Character;
import cluedo.ColorPawn;
import cluedo.Pawn;
import cluedo.Room;
import cluedo.Weapon;


/** 
 * Questa interfaccia definisce i metodi che possono essere invocati sull'oggetto remoto
 * Note: un player puo' essere proprietario di al piu' un gruppo, di cui ne e'
 * anche membro; un player e' membro di al piu' un gruppo. 
 **/ 
public interface PlayerIntf extends Remote {
	
	/**
	 * Numero minimo di player per poter iniziare una partita
	 */
	public static final int MIN_PLAYERS= 3;
	/**
	 * Numero massimo di player che possono partecipare ad una partita
	 */
	public static final int MAX_PLAYERS= 6;
	
	// METODI DI SUPPORTO
	
	/**
	 * Invia un messaggio di chat al player
	 * @param sender mittente del messaggio
	 * @param seq numero di sequenza
	 * @param msg testo del messaggio
	 * @throws RemoteException
	 */
    public void sendChatMessage(String sender, int seq, String msg) throws RemoteException;

    
    /**
     * Invia un'informazione di gioco al player
     * @param sender il player che ha inviato l'informazione (mittente del messaggio)
     * @param seq numero di sequenza o -1 se e' un messaggio unicast
     * @param playerName:
     * 		il player che ha confutato la mia ipotesi se il parametro type e' "Refuted" 
	 * 		oppure il nuovo proprietario del gruppo se il parametro type e' "ChangeOwner"
	 * 		oppure il player a cui ho confutato l'ipotesi se il parametro type e' "RefuteSent"
	 * 		oppure null.
     * @param msg informazione supplementare che ha un certo significato in base al parametro type
	 * @param type tipo di informazione (usato per creare le informazioni)
     * @throws RemoteException
     */
    public void sendInfo(String sender, int seq, String playerName, String msg, String type) throws RemoteException;
    
    /**
     * Restituisce il nickname del player
     * @return nickname
     * @throws RemoteException
     */
    public String getNickname() throws RemoteException;
    
    // METODI DI REGISTRAZIONE
    
    /**
     * Notifica il player che e' stato creato un nuovo gruppo di gioco
     * @param groupName nome del gruppo di gioco creato
     * @param owner proprietario del gruppo di gioco
     * @throws RemoteException
     */
    public void notifyAddPlayGroup(String groupName, PlayerIntf owner) throws RemoteException;
    
    /**
     * Notifica il player che e' stato rimosso un gruppo di gioco
     * @param groupName nome del gruppo di gioco rimosso
     * @throws RemoteException
     */
    public void notifyDelPlayGroup(String groupName) throws RemoteException;
    
    /**
     * Notifica il player che il proprietario di un gruppo e' cambiato
     * @param groupName nome del gruppo che ha cambiato proprietario
     * @param newOwner nuovo proprietario
     * @throws RemoteException
     */
    public void notifyChangePlayGroupOwner(String groupName, PlayerIntf newOwner) 
    		throws RemoteException;
    
    /**
     * Richiede di potersi aggiungere al gruppo di gioco in fase di creazione di 
     * cui e' proprietario il player su cui viene invocato.
     * La richiesta puo' non andare a buon fine se il gruppo ha gia' raggiunto
     * il numero massimo di membri, se nel frattempo la partita e' stata
     * iniziata o il payer invocato non e' proprietario di un gruppo.
     * 
     * Questo metodo notifica tutti i membri del gruppo, compreso chi ha invocato la
     * richiesta e il suo proprietario. Questo perche' chi ha invocato la 
     * richiesta ha bisogno di conoscere la lista dei membri del gruppo.
     * 
     * Non viene inviato in multicast.
     * @param sender nickname del player che ha inviato la richiesta (mittente del messaggio)
     * @param player player che effettua la richiesta
     * @return true in caso di successo, false altrimenti
     * @throws RemoteException 
     */
    public boolean joinPlayGroup(String sender, PlayerIntf player) throws RemoteException;
    
    /**
     * Richiede di poter essere rimosso dal gruppo di gioco di cui e' 
     * proprietario il player su cui viene invocato.
     * E' possibile uscire dal gruppo in qualsiasi momento: sia a partita non
     * iniziata, sia durante i preparativi della partita, sia durante lo
     * svolgimento del gioco.
     * Il proprietario non puo' usare questo metodo per rimuoversi dal gruppo.
     * 
     * Questo metodo notifica tutti i membri del gruppo compreso il suo proprietario, tranne
     * chi ha fatto richiesta di uscire dal gruppo. Nota che il 
     * proprietario potrebbe essere cambiato, ovvero esce l'attuale proprietario
     * il cui posto viene preso dal player successivo.
     * 
     * Non viene inviato in multicast.
     * 
     * @param sender il nickname del player che effettua la richiesta (mittente del messaggio)
     * @param seq numero di sequenza
     * @throws RemoteException 
     */
    public void exitPlayGroup(String sender, int seq) throws RemoteException;
    
    /**
     * Notifica il player su cui viene invocato che il numero dei membri del 
     * gruppo e' cambiato fornendone la lista attuale. Questo metodo deve
     * essere invocato su tutti membri, compreso il proprietario del gruppo.
     * La lista dei membri del gruppo e' una lista ordinata di player, di cui 
     * il primo elemento ne costituisce il proprietario.
     * Questa notifica viene invocata solo quando la partita non e' ancora
     * iniziata. Solo in questo caso i membri del gruppo di gioco possono 
     * variare. Vedi notifyMemberIsDead() per il caso di uscita di un membro
     * a partita iniziata.
     * Il nome del gruppo e' implicito in quanto un player puo' unirsi al piu'
     * ad un gruppo.
     * @param sender nickname del player che ha iniviato la notifica. E' il proprietario (vecchio o nuovo) del gruppo. (mittente del messaggio)
     * @param seq numero di sequenza
     * @param members membri del gruppo di gioco (nota che sono sempre e solo membri "vivi")
     * @param seqs sequence number dei player
     * @throws RemoteException
     */
    public void notifyGroupMembers(String sender, int seq, 
    		LinkedHashMap<String, PlayerIntf> members,
    		LinkedHashMap<String, Integer> seqs
    		) throws RemoteException;
    
    
    // ZOMBIE MORTO (PLAYER USCITO DALLA PARTITA)
    
    /**
     * Notifica il player su cui viene invocato che un player 
     * e' uscito dal gruppo (per qualsiasi ragione) quando la partita
     * era gia' iniziata. Questo metodo deve essere invocato su tutti membri, 
     * compreso il proprietario del gruppo.
     * Se esce il proprietario, diventa proprietario il primo player ancora 
     * vivo.
     * Il nome del gruppo e' implicito in quanto un player puo' unirsi al piu'
     * ad un gruppo.
     * @param sender nickname del player che ha inviato la notifica, ovvero il proprietario del gruppo (mittente del messaggio)
     * @param seq numero di sequenza
     * @param playerName nickname del player che e' uscito
     * @throws RemoteException
     */
    public void notifyPlayerExited(String sender, int seq, String playerName) throws RemoteException;
    
    
    // ZOMBIE MORTO (CRASH)
    
    /**
     * Notifica il player su cui viene invocato, che un altro player e' andato in crash
     * @param sender nickname del player che ha iniviato la notifica (mittente del messaggio)
     * @param seq numero di sequenza
     * @param playerName il nickname del player andato in crash
     * @throws RemoteException
     */
    public void notifyPlayerCrashed(String sender, int seq, String playerName) throws RemoteException;
    
    
    
    // METODI PER I PREPARATIVI DELLA PARTITA
    
    /**
     * Notifica il player su cui viene invocato, che il proprietario del gruppo
     * ha deciso di iniziare la partita. Questo metodo deve
     * essere invocato su tutti membri, compreso il proprietario del gruppo.
     * @param sender nickname del player che ha iniviato la notifica (e' sempre il proprietario) (mittente del messaggio)
     * @param seq numero di sequenza
     * @throws RemoteException
     */
    public void notifyPlayStarted(String sender, int seq) throws RemoteException;
    
    /**
     * Notifica il player su cui viene invocato, quale pedina ha scelto un altro
     * player.
     * Viene utilizzato per escludere, al momento della selezione di una
     * pedina, quelle scelte da altri giocatori
     * @param sender nickname del player che ha scelto la pedina (mittente del messaggio)
     * @param seq numero di sequenza
     * @param playerPawn la pedina scelta
     * @throws RemoteException
     */
    public void notifyPlayerPawn(String sender, int seq, Pawn playerPawn) throws RemoteException;

	/** 
	 * Notifica il numero ottenuto da un player dopo che ha tirato il dado 
	 * necessario per lo spareggio.
     * Viene comunicato a tutti i Player escluso chi ha tirato il dado.
     * Questo tiro di dado e' valido solo per lo spareggio per determinare il 
     * primo giocatore.
     * @param sender il nickname del giocatore che ha tirato il dado (mittente del messaggio)
     * @param seq numero di sequenza
     * @param num il numero ottenuto
     * */
	public void throwTieBreakDice(String sender, int seq, int num) throws RemoteException;
	
    /**
     * Utilizzato dal proprietario del gruppo per distribuire le carte a tutti i 
     * giocatori. Viene richiamato anche sul proprietario stesso.
     * La distrubuzione comprende le carte della soluzione e le carte degli 
     * altri giocatori.
     * 
     * I singoli player prelevano le carte dal mazzo nel seguente modo.
     * Sia n il numero di player. Il j-esimo player preleva le carte dal mazzo 
     * partendo dalla j-esima carta a passi di n.
     * @param sender nickname del player che ha iniviato la notifica (mittente del messaggio)
     * @param seq numero di sequenza
	 * @param room la carta della stanza della soluzione
	 * @param weapon la carta arma della soluzione
	 * @param character la carta personaggio della soluzione
	 * @param deck le altre carte (mescolate) del mazzo
	 * @throws RemoteException
	 */
	public void setDeck(String sender, int seq, Room room, Weapon weapon, Character character, List<Card> deck)
			throws RemoteException;
	
	
	//METODI PER GESTIRE TOLLERANZA AI GUASTI
	
	/**
	 * Metodo, usato da un player che non ha il turno di gioco, per controllare se gli altri player hanno fatto crash
	 * @return ritorna true se il player e' vivo, false se il player e' uno zombie oppure ha fatto crash
	 * @throws RemoteException se il player su cui e' invocato ha fatto crash
	 */
	public boolean areYouAlive() throws RemoteException;
	
    
    // METODI PER GIOCARE
    
    /**
     * Ritorna il colore della pedina del giocatore
     * @return il colore della pedina di un determinato giocatore
     * @throws RemoteException
     */
    public ColorPawn getPawnColor() throws RemoteException;
    
    /**
   	 * Un giocatore ha mosso la sua pedina
   	 * @param sender il player che ha mosso la pedina (mittente del messaggio)
     * @param seq numero di sequenza
   	 * @param x la coordinate x della cella in cui si e' spostata la pedina
   	 * @param y la coordinata y delle cella in cui si e' spostata la pedina
   	 */
    public void movePawn(String sender, int seq, int x,int y) throws RemoteException;
       
    /**
     * Viene comunicato il vincitore della partita
     * @param sender il vincitore (mittente del messaggio) o -1 se e' un messaggio unicast
     * @throws RemoteException
     * */
	public void winner(String sender, int seq) throws RemoteException;
	
	/**
	 * Viene comunicato che un giocatore ha terminato il suo turno
	 * E' inviato atutti i giocatori anche a chi ha terminato il turno
	 * @param sender il giocatore che passa il turno (mittente del messaggio)
     * @param seq numero di sequenza o -1 se e' un messaggio unicast
	 * @throws RemoteException
	 */
	public void endTurn(String sender, int seq) throws RemoteException;
	
	/**
	 * Controlla se puoi rispondere all'ipotesi fatta da un giocatore
	 * @param sender il giocatore che ha fatto l'ipotesi (mittente del messaggio)
     * @param seq numero di sequenza
	 * @param character la carta personaggio ipotizzata
	 * @param weapon la carta arma ipotizzata
	 * @param room la carta della stanza ipotizzata
	 * @throws RemoteException
	 */
	public void checkAssumption(String sender, int seq, Character character,Weapon weapon, Room room) throws RemoteException;

	
	/* 
	 * checkSolution non c'e' perche' il client possiede gia' le carte della soluzione e 
	 * quindi non deve chiedere agli altri se questa e' corretta
	*/
	
	/**
	 * Un player smentisce la tua ipotesi.
	 * @param sender il giocatore che contesta la tua ipotesi (mittente del messaggio)
	 * @param seq numero di sequenza
	 * @param card la carta che confuta l'ipotesi oppure null se il player non puo' confutare l'ipotesi
	 * @throws RemoteException
	 */
    public void refuteAssumption(String sender,int seq, Card card) throws RemoteException; // invocato sul player che ha formulato l'ipotesi per confutarla (il giocatore mostra la carta che confuta l'ipotesi)
    
    
}
